#if _MSC_VER
 #pragma once
#endif // _MSC_VER

#ifndef __HERZELEID_BASICLOADER_INCLUDED__
 #define __HERZELEID_BASICLOADER_INCLUDED__
 #include "HerzeleidRendererModelResources.hxx"
 #include "HerzeleidCoreRenderer3.hxx"
 #include "HerzeleidReaderWriter.hxx"

 #ifdef HERZELEID_DESKTOP
  #define ref
  #define internal public
 #else
 #endif

// A simple loader class that provides support for loading shaders, textures 
// from files on disk. Provides synchronous and asynchronous methods.
HerzeleidRendererResourcesNamespaceBegin ref class BasicLoader
{
	typedef HerzeleidUtilityNamespaceImpl::BasicReaderWriter Reader;
	typedef HerzeleidRendererCoreNamespaceImpl::Device3 Device3;
#ifdef HERZELEID_DESKTOP
	typedef std::shared_ptr<Standard::String16> StringArg; TinyTypeDecl( StringArg );
	typedef std::unique_ptr<Reader> UniquePtrReader;
	TinyTypeDecl( UniquePtrReader );
#else
	typedef Reader^ UniquePtrReader;
	typedef Platform::String^ StringArg;
#endif
	typedef Concurrency::task<Void> AsyncAction;
	TinyTypeDecl( AsyncAction );
	TinyTypeDecl( Device3 );
	typedef Void Action;

private:

	// Members and closed functionality 

	Device3Ptr m_Device; // Used for creating the resources from memory. 
	UniquePtrReader m_Reader; // Used for reading the resources from files on disk. 

	StringArg GetExtension( 
		_In_ StringArg wszFileName 
		);

	Action CreateTexture(
		_In_ Bool bDecodeAsDDS,
        _In_reads_bytes_(uDataSize) BytePtr pData,
        _In_ UInt32 uDataSize,
        _Outptr_result_nullonfailure_ Texture2Address ppTexture,
        _Outptr_opt_result_nullonfailure_ ShaderResourceViewAddress ppView,
        _In_opt_ StringArg wszDebugName
		);

    Action CreateInputLayout(
        _In_reads_bytes_(uBytecodeSize) BytePtr pBytecode,
        _In_ UInt32 uBytecodeSize,
        _In_reads_opt_(uLayoutDescNumElements) D3D11_INPUT_ELEMENT_DESC pLayoutDescElements[],
        _In_ UInt32 uLayoutDescNumElements,
        _Outptr_opt_result_nullonfailure_ InputLayoutAddress ppLayout,
        _In_opt_ StringArg wszDebugName
        );

internal:

	BasicLoader(
		_In_ Device3Ptr pDevice
		);

	// Sync methods 

	Action LoadTexture(
		_In_ StringArg wszFileName, 
        _Outptr_result_nullonfailure_ Texture2Address ppTexture,
        _Outptr_opt_result_nullonfailure_ ShaderResourceViewAddress ppView
		);
    Action LoadShader(
        _In_ StringArg wszFileName,
        _In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC pLayoutDescElements[],
        _In_ UInt32 uLayoutDescNumElements,
        _Outptr_result_nullonfailure_ VertexShaderAddress ppShader,
        _Outptr_opt_result_nullonfailure_ InputLayoutAddress ppLayout
        );
    Action LoadShader(
        _In_ StringArg wszFileName,
        _In_reads_opt_(uNumEntries) const D3D11_SO_DECLARATION_ENTRY streamOutDeclaration[],
        _In_ UInt32 uNumEntries,
        _In_reads_opt_(uNumStrides) const UInt32 pBufferStrides[],
        _In_ UInt32 uNumStrides,
        _In_ UInt32 uRasterizedStream,
        _Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
        );
    Action LoadShader(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ HullShaderAddress ppShader
        );
    Action LoadShader(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ DomainShaderAddress ppShader
        );
    Action LoadShader(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
        );
    Action LoadShader(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ PixelShaderAddress ppShader
        );
    Action LoadShader(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ ComputeShaderAddress ppShader
        );

	// Async methods 
	
	AsyncAction LoadTextureAsync(
		_In_ StringArg wszFileName, 
        _Outptr_opt_result_nullonfailure_ Texture2Address ppTexture,
        _Outptr_opt_result_nullonfailure_ ShaderResourceViewAddress ppView
		);
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC pLayoutDescElements[],
        _In_ UInt32 uLayoutDescNumElements,
        _Outptr_result_nullonfailure_ VertexShaderAddress ppShader,
        _Outptr_opt_result_nullonfailure_ InputLayoutAddress ppLayout
        );
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _In_reads_opt_(uNumEntries) const D3D11_SO_DECLARATION_ENTRY pStreamOutDeclaration[],
        _In_ UInt32 uNumEntries,
        _In_reads_opt_(uNumStrides) const UInt32 pBufferStrides[],
        _In_ UInt32 uNumStrides,
        _In_ UInt32 uRasterizedStream,
        _Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
        );
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ HullShaderAddress ppShader
        );
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ DomainShaderAddress ppShader
        );
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
        );
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ PixelShaderAddress ppShader
        );
    AsyncAction LoadShaderAsync(
        _In_ StringArg wszFileName,
        _Outptr_result_nullonfailure_ ComputeShaderAddress ppShader
        );

} HerzeleidRendererResourcesNamespaceEnd;

#ifdef HERZELEID_DESKTOP
#undef ref
#undef internal
#else
#endif

#endif // !HERZELEID_BASICLOADER_INCLUDED__
